// Learn with Examples, 2020, MIT license
#include <systemc> // include the systemC header file
#include <fcntl.h>
#include <sys/mman.h>
#include <unistd.h>
#include <cstring>


using namespace sc_core; // use namespace

#define SHM_NAME "my_shm"
#define SHM_SIZE 4096

SC_MODULE(SharedMemory) {
    int shm_fd;
    void* ptr;

    SC_CTOR(SharedMemory) {
        // 打开共享内存对象
        shm_fd = shm_open(SHM_NAME, O_CREAT | O_RDWR, 0666);
        if (shm_fd == -1) {
            SC_REPORT_ERROR("SharedMemory", "Failed to open shared memory object");
            return;
        }
		int ret = ftruncate(shm_fd, SHM_SIZE);  // 共享内存大小为 4KB
        // 将共享内存映射到进程地址空间
        ptr = mmap(0, SHM_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0);
        if (ptr == MAP_FAILED) {
            SC_REPORT_ERROR("SharedMemory", "Failed to map shared memory");
            return;
        }
		printf("shared memory demo start\n");

        SC_THREAD(read_shared_memory);
    }

    ~SharedMemory() {
        // 解除内存映射并关闭共享内存对象
        munmap(ptr, SHM_SIZE);
        close(shm_fd);
    }

    void read_shared_memory() {
        uint32_t * wrvld = static_cast<uint32_t*>(ptr);
		uint32_t* wrrdy = static_cast<uint32_t*>(ptr+4);
		uint32_t* wraddr = static_cast<uint32_t*>(ptr+8);
		uint32_t* wrdata = static_cast<uint32_t*>(ptr+0x0C);
		uint32_t* rdvld = static_cast<uint32_t*>(ptr+0x10);
		uint32_t* rdrdy = static_cast<uint32_t*>(ptr+0x14);
		uint32_t* rdaddr = static_cast<uint32_t*>(ptr+0x18);
		uint32_t* rddata = static_cast<uint32_t*>(ptr+0x1C);
        while (true) {
            if(*wrvld){
				printf("write addr = %x; data = %x\n", *wraddr, *wrdata);
				*wrvld = 0;
				*wrrdy = 1;
				if(*wraddr == 0x80){
					*(static_cast<uint32_t*>(ptr+0x20)) = 1;
                    			printf("trigger interrupt\n");
				}
			}
			if(*rdvld){
				printf("read addr = %x; data = %x\n", *rdaddr, *rddata);
				*rdvld = 0;
				*rdrdy = 1;
			}
        }
    }
};

void hello1() { // a normal c++ function
  std::cout << "Hello world using approach 1" << std::endl;
}

struct HelloWorld : sc_module { // define a systemC module
  SC_CTOR(HelloWorld) {// constructor function, to be explained later
    SC_METHOD(hello2); // register a member function to the kernel
  }
  void hello2(void) { // a function for systemC simulation kernel, void inside () can be omitted
    std::cout << "Hello world using approach 2" << std::endl;
  }
};

int sc_main(int, char*[]) { // entry point
  //hello1(); // approach #1: manually invoke a normal function
  //HelloWorld helloworld("helloworld"); // approach #2, instantiate a systemC module
  SharedMemory shared_memory("sharedmemory");
  sc_start(); // let systemC simulation kernel to invoke helloworld.hello2();
  return 0;
}
